#include"../xxxpcsc/log.h"
#include"../xxxpcsc/config.h"
#include<yaml-cpp/yaml.h>
#include<iostream>

//解决相同name查找时的报错
xxXPCSC::ConfigVar<int>::ptr g_int_value_config = 
        xxXPCSC::Config::Lookup("system.port",(int)8080,"system port");
xxXPCSC::ConfigVar<float>::ptr g_int_valuex_config = 
        xxXPCSC::Config::Lookup("system.port",(float)8080,"system port");

xxXPCSC::ConfigVar<float>::ptr g_float_value_config = 
        xxXPCSC::Config::Lookup("system.value",(float)10.2f,"system value");

xxXPCSC::ConfigVar<std::vector<int>>::ptr g_int_vec_value_config = 
        xxXPCSC::Config::Lookup("system.int_vec",std::vector<int>{1,2},"system int vec");

xxXPCSC::ConfigVar<std::list<int>>::ptr g_int_list_value_config = 
        xxXPCSC::Config::Lookup("system.int_list",std::list<int>{1,2},"system int list");

xxXPCSC::ConfigVar<std::set<int>>::ptr g_int_set_value_config = 
        xxXPCSC::Config::Lookup("system.int_set",std::set<int>{1,2},"system int set");

xxXPCSC::ConfigVar<std::unordered_set<int>>::ptr g_int_uset_value_config = 
        xxXPCSC::Config::Lookup("system.int_uset",std::unordered_set<int>{1,2},"system int uset");

xxXPCSC::ConfigVar<std::map<std::string, int> >::ptr g_str_int_map_value_config =
    xxXPCSC::Config::Lookup("system.str_int_map", std::map<std::string, int>{{"k",2}}, "system str int map");

xxXPCSC::ConfigVar<std::unordered_map<std::string, int> >::ptr g_str_int_umap_value_config =
    xxXPCSC::Config::Lookup("system.str_int_umap", std::unordered_map<std::string, int>{{"k",2}}, "system str int map");

void print_yaml(const YAML::Node& node,int level){
        if(node.IsScalar()){
                XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<std::string(level+4,' ')
                <<node.Scalar()<<"-"<<node.Type()<<"-"<<level;
        }else if(node.IsNull()){
                XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<std::string(level+4,' ')
                <<"null -"<<"-"<<node.Type()<<"-"<<level;
        }else if(node.IsMap()){
                for(auto it = node.begin();it!=node.end();it++){
                        XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<std::string(level+4,' ')
                        <<it->first<<"-"<<it->second.Type()<<"-"<<level;
                        print_yaml(it->second,level+1);
                }
        }else if(node.IsSequence()){
                for(size_t i=0;i<node.size();i++){
                        XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<std::string(level+4,' ')
                        <<i<<"-"<<node[i].Type()<<"-"<<level;
                        print_yaml(node[i],level+1);
                }
        }
}
void test_yaml(){
        YAML::Node root = YAML::LoadFile("../bin/conf/log.yaml");
        print_yaml(root,0);
        //XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<root;
}
void test_config(){
    XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<"before:"<<g_int_value_config->getValue();
    XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<"before:"<<g_float_value_config->toString();

#define XX(g_var,name,prefix) \
    { \
        auto& v= g_var->getValue(); \
        for(auto& i:v){ \
                XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<#prefix " "#name":"<<i; \
        } \
		XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<#prefix " "#name" yaml:"<<g_var->toString();\
	}

#define XX_M(g_var, name, prefix) \
    { \
        auto& v = g_var->getValue(); \
        for(auto& i : v) { \
            XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT()) << #prefix " " #name ": {" \
                    << i.first << " - " << i.second << "}"; \
        } \
        XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT()) << #prefix " " #name " yaml: " << g_var->toString(); \
    }

    XX(g_int_vec_value_config,int_vec,before);
    XX(g_int_list_value_config,int_list,before);
	XX(g_int_set_value_config,int_set,before);
	XX(g_int_uset_value_config,int_uset,before);
	XX_M(g_str_int_map_value_config, str_int_map, before);
	XX_M(g_str_int_umap_value_config, str_int_umap, before);

    YAML::Node root = YAML::LoadFile("../bin/conf/test_config.yaml"); 
    xxXPCSC::Config::LoadFromYaml(root);

    XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<"after:"<<g_int_value_config->getValue();
    XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<"after:"<<g_float_value_config->toString();

    XX(g_int_vec_value_config,int_vec,after);
    XX(g_int_list_value_config,int_list,after);
	XX(g_int_set_value_config,int_set,before);
	XX(g_int_uset_value_config,int_uset,after);
	XX_M(g_str_int_map_value_config, str_int_map, after);
	XX_M(g_str_int_umap_value_config, str_int_umap, after);
}

class Person{
public:
 	Person() {};
	/*
	std::string 字符串不可以初始化为NULL，虽然能通过编译，但是会出现运行错误。
	std::string 使用以下两种初始化为空的方式：
	*/
	std::string m_name ;
	int m_age=0;
	bool m_sex =0;
	std::string toString() const {
        std::stringstream ss;
        ss << "[Person name=" << m_name
           << " age=" << m_age
           << " sex=" << m_sex
           << "]";
        return ss.str();
    }

    bool operator==(const Person& oth) const {
        return m_name == oth.m_name
            && m_age == oth.m_age
            && m_sex == oth.m_sex;
    }
};

//对类的偏特化
namespace xxXPCSC{

    template<>
	class LexicalCast<std::string, Person> {
	public:
    Person operator()(const std::string& v) {
        YAML::Node node = YAML::Load(v);
        Person p;
        p.m_name = node["name"].as<std::string>();
        p.m_age = node["age"].as<int>();
        p.m_sex = node["sex"].as<bool>();
        return p;
    }
	};

	template<>
	class LexicalCast<Person, std::string> {
	public:
    std::string operator()(const Person& p) {
        YAML::Node node;
        node["name"] = p.m_name;
        node["age"] = p.m_age;
        node["sex"] = p.m_sex;
        std::stringstream ss;
        ss << node;
        return ss.str();
    }
	};
	
}

xxXPCSC::ConfigVar<Person>::ptr g_person = 
        xxXPCSC::Config::Lookup("class.person", Person(), "system person");

xxXPCSC::ConfigVar<std::map<std::string, Person>>::ptr g_person_map =
    xxXPCSC::Config::Lookup("class.map", std::map<std::string, Person>(), "system person");

xxXPCSC::ConfigVar<std::map<std::string, std::vector<Person> > >::ptr g_person_vec_map =
    xxXPCSC::Config::Lookup("class.vec-map", std::map<std::string, std::vector<Person> >(), "system person");

void test_class(){ 
	XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT()) << "before: " << g_person->getValue().toString() << " - " << g_person->toString();
	#define XX_PM(g_var, prefix) \
    { \
        auto m = g_var->getValue(); \
        for(auto& i : m) { \
            XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT()) <<  prefix << ": " << i.first << " - " << i.second.toString(); \
        } \
        XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT()) <<  prefix << ": size=" << m.size(); \
    }
    g_person->addListener(10,[](const Person& old_value,const Person& new_value){
        XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<"old_value= "<<old_value.toString()<<" new_value= "<<new_value.toString();
    });
    
    XX_PM(g_person_map, "class.map before");
	XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<"before: " << g_person_vec_map->toString();

    YAML::Node root = YAML::LoadFile("../bin/conf/test_config.yaml"); 
    xxXPCSC::Config::LoadFromYaml(root);

    XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT()) << "after: " << g_person->getValue().toString() << " - " << g_person->toString();
    XX_PM(g_person_map, "class.map after");
	XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<"after: " << g_person_vec_map->toString();
}

void test_log(){
    static xxXPCSC::Logger::ptr system_log = XXXPCSC_LOG_NAME("system");
    XXXPCSC_LOG_INFO(system_log)<<"hello system"<<std::endl;

    

    YAML::Node root = YAML::LoadFile("../bin/conf/log.yaml");
    xxXPCSC::Config::LoadFromYaml(root);

    XXXPCSC_LOG_INFO(system_log)<<"hello system"<<std::endl;
}

int main(){
    //test_yaml();
    // test_config();
	//test_class();
    test_log();
    return 0;
}